package thread;

import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author SWJ
 * @create 2021-06-25 11:46
 * 7本类用来测试暴力反射
 */
public class TestReflaction2 {
    @Test
    public void getFields() throws Exception {
        //1.获取目标资源对应的字节码对象
        Class<?> clazz = Person.class;
        //2.获取指定名称的私有属性
        Field field = clazz.getDeclaredField("name");
        //3.根据获取到的属性对象拿到它的类型
        System.out.println(field.getType().getName());
        System.out.println(field.getType());
        //4.设置属性的值
        //4.1 没有对象就通过反射的方式创建对象
        Object obj = clazz.newInstance();
        //4.2 暴力反射！！！注意！！！要设置私有可见，不然访问不了
        field.setAccessible(true);
        //4.3刚刚获取到的name属性对象设置值
        /*注意需要设置两个参数：哪个对象的属性值，以及要设置一个什么值
         * set(m,n) m-给哪个对象设置值  n-给这个对象的属性设置一个什么值*/
        field.set(obj, "林冲");
        //4.4打印刚刚给属性设置的值
        /*注意还是需要指定获取的是哪个对象的这个属性的值*/
        System.out.println(field.get(obj));
    }

    /*单元测试 2 ：通过暴力反射获取与使用方法*/
    @Test
    public void getFunction() throws Exception {
        //1.获取目标资源对应的字节码对象
        Class<?> clazz = Person.class;
        //2.通过暴力反射获取私有方法
        /*本方法的参数列表是getDeclaredMethod(name,x,y,z...)
         * name:指的是要获取方法的名字
         * x,y,z...可变参数，指的是要获取方法的参数类型，注意是字节码对象“.class”*/
        Method method = clazz.getDeclaredMethod("add", String.class, int.class);
        //3.1没有对象就通过反射创建对象
        Object obj = clazz.newInstance();
        //3.2如果想要执行私有的方法，也要设置私有可见
        method.setAccessible(true);
        //3.3执行获取到的这个私有方法
        /*invoke()用来调用目标方法，参数1是执行哪个对象的这个方法
        后续的参数是执行目标方法时传入的参数，这个参数是可变参数，根据目标方法的具体情况来写*/
        method.invoke(obj, "李四儿", 18);
    }
}
